/*
对HTML Element的包装
*/
var Element = new Native({

 //族名，为$type方法提供精准类型
 name: 'Element',

 //包装扩展的原型
 legacy: window.Element,

 //初始化，使用Document对象的newElement创建对象
 initialize: function(tag, props){

  //先看有没有特殊的HTML Element
  var konstructor = Element.Constructors.get(tag);

  //对特殊的HTML Element对象特别处理
  if (konstructor) return konstructor(props);

  //如果提供标签名，根据标签名创建HTML Element对象
  if (typeof tag == 'string') return document.newElement(tag, props);

  //设置属性
  return $(tag).set(props);
 },

 //执行后续处理,每为Element增加一个扩展,Elements也会同时实现
 afterImplement: function(key, value){
  if (!Array[key]) Elements.implement(key, Elements.multi(key));
  Element.Prototype[key] = value;
 }

});

Element.Prototype = {$family: {name: 'element'}};

Element.Constructors = new Hash;

 

//同时对Element和Document对象进行扩展
Native.implement([Element, Document], {

 //根据选择符选择一个子Element
 getElement: function(selector, notrash){
  return $(this.getElements(selector, true)[0] || null, notrash);
 },

 //根据选择符选择子Element
 getElements: function(tags, nocash){
  tags = tags.split(',');
  var elements = [];
  var ddup = (tags.length > 1);
  tags.each(function(tag){
   var partial = this.getElementsByTagName(tag.trim());
   (ddup) ? elements.extend(partial) : elements = partial;
  }, this);
  return new Elements(elements, {ddup: ddup, cash: !nocash});
 }

});

//用于获取保存在当前Element下的临时对象，参考Fx.Tween和Drag
Element.Storage = {

 get: function(uid){
  return (this[uid] || (this[uid] = {}));
 }

};

//相当于当前Element的四个位置的DOM插入
Element.Inserters = new Hash({

 //在context指代的Element之前插入eleemnt
 before: function(context, element){
  if (element.parentNode) element.parentNode.insertBefore(context, element);
 },

 //在context指代的Element之后插入eleemnt
 after: function(context, element){
  if (!element.parentNode) return;
  var next = element.nextSibling;
  (next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context);
 },

 //在context指代的Element内最后插入eleemnt
 bottom: function(context, element){
  element.appendChild(context);
 },

 //在context指代的Element内首位插入eleemnt
 top: function(context, element){
  var first = element.firstChild;
  (first) ? element.insertBefore(context, first) : element.appendChild(context);
 }

});

//别名
Element.Inserters.inside = Element.Inserters.bottom;

//生成injectTop/grabTop之类的快捷方式
Element.Inserters.each(function(value, key){

 var Key = key.capitalize();

 //injectTop,injectBefore,injectAfter,injectBottom
 Element.implement('inject' + Key, function(el){
  value(this, $(el, true));
  return this;
 });

 //grabTop,grabBefore,grabAfter,grabBottom
 Element.implement('grab' + Key, function(el){
  value($(el, true), this);
  return this;
 });

});

Element.implement({

 //当前Element所属的Document
 getDocument: function(){
  return this.ownerDocument;
 },

 //当前Element所属的Window
 getWindow: function(){
  return this.ownerDocument.getWindow();
 },

 //根据ID查找当前Element下的对象
 getElementById: function(id, nocash){
  var el = this.ownerDocument.getElementById(id);
  if (!el) return null;
  for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
   if (!parent) return null;
  }
  return $.element(el, nocash);
 },

 //万能的setter
 set: function(prop, value){
  switch ($type(prop)){
   case 'object':
    for (var p in prop) this.set(p, prop[p]);
    break;
   case 'string':
    var property = Element.Properties.get(prop);
    (property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value);
  }
  return this;
 },

 //万能的getter
 get: function(prop){
  var property = Element.Properties.get(prop);
  return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop);
 },

 //万能的eraser
 erase: function(prop){
  var property = Element.Properties.get(prop);
  (property && property.erase) ? property.erase.apply(this, Array.slice(arguments, 1)) : this.removeProperty(prop);
  return this;
 },

 //判断当前Element是否匹配指定标签名
 match: function(tag){
  return (!tag || Element.get(this, 'tag') == tag);
 },

 //根据where指定的位置，将当前Element注入到el
 inject: function(el, where){
  Element.Inserters.get(where || 'bottom')(this, $(el, true));
  return this;
 },

 //根据where指定的位置，使当前Element作为el的父Element
 wraps: function(el, where){
  el = $(el, true);
  return this.replaces(el).grab(el, where);
 },

 //和inject相反
 grab: function(el, where){
  Element.Inserters.get(where || 'bottom')($(el, true), this);
  return this;
 },

 //追加文本
 appendText: function(text, where){
  return this.grab(this.getDocument().newTextNode(text), where);
 },

 //将多个对象追加到当前Element内
 adopt: function(){
  Array.flatten(arguments).each(function(element){
   element = $(element, true);
   if (element) this.appendChild(element);
  }, this);
  return this;
 },

 //从DOM节点中删除
 dispose: function(){
  return (this.parentNode) ? this.parentNode.removeChild(this) : this;
 },

 //从当前Element克隆出新的Element，contents指定是否包含子节点，keepid指定是否忽略id属性
 clone: function(contents, keepid){
  switch ($type(this)){
   case 'element':
    var attributes = {};
    for (var j = 0, l = this.attributes.length; j < l; j++){
     var attribute = this.attributes[j], key = attribute.nodeName.toLowerCase();
     var value = (key == 'style' && this.style) ? this.style.cssText : attribute.nodeValue;
     if (!$chk(value) || key == 'uid' || (key == 'id' && !keepid)) continue;
     if (value != 'inherit' && ['string', 'number'].contains($type(value))) attributes[key] = value;
    }
    var element = new Element(this.nodeName.toLowerCase(), attributes);
    if (contents !== false){
     for (var i = 0, k = this.childNodes.length; i < k; i++){
      var child = Element.clone(this.childNodes[i], true, keepid);
      if (child) element.grab(child);
     }
    }
    return element;
   //如果当前是文本节点
   case 'textnode': return document.newTextNode(this.nodeValue);
  }
  return null;
 },

 //替换节点
 replaces: function(el){
  el = $(el, true);
  el.parentNode.replaceChild(this, el);
  return this;
 },

 //是否使用指定css类名
 hasClass: function(className){
  return this.className.contains(className, ' ');
 },

 //添加指定css类名
 addClass: function(className){
  if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
  return this;
 },

 //移除指定css类名
 removeClass: function(className){
  this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1').clean();
  return this;
 },

 //切换指定css类名
 toggleClass: function(className){
  return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
 },

 //获取运行时的样式属性
 getComputedStyle: function(property){
  //IE
  if (this.currentStyle) return this.currentStyle[property.camelCase()];
  //非IE
  var computed = this.getWindow().getComputedStyle(this, null);
  return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null;
 },

 //清空当前Element，包括内部节点的删除和内存释放
 empty: function(){
  $A(this.childNodes).each(function(node){
   Element.empty(node);
   this.removeChild(node);
   memfree(node);
  }, this);
  return this;
 },

 //销毁当前Element，删除所有有关的一切
 destroy: function(){
  memfree(this.empty().dispose());
  return null;
 },

 //获取选中的子项，仅当<select multi>有效
 getSelected: function(){
  return $A(this.options).filter(function(option){
   return option.selected;
  });
 },

 //将当前Element内的表单项数据转为查询串格式，以用于Ajax或get方式的提交
 toQueryString: function(){
  var queryString = [];
  this.getElements('input, select, textarea').each(function(el){
   if (!el.name || el.disabled) return;
   var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){
    return opt.value;
   }) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value;
   $splat(value).each(function(val){
    if (val) queryString.push(el.name + '=' + encodeURIComponent(val));
   });
  });
  return queryString.join('&');
 },

 //读取属性值，包括自定义属性
 getProperty: function(attribute){
  var EA = Element.Attributes, key = EA.Props[attribute];
  var value = (key) ? this[key] : this.getAttribute(attribute, 2);
  return (EA.Bools[attribute]) ? !!value : (key) ? value : value || null;
 },

 //根据属性列表读取相应值，以objecct方式返回结果
 getProperties: function(){
  var args = $A(arguments);
  return args.map(function(attr){
   return this.getProperty(attr);
  }, this).associate(args);
 },

 //属性设置
 setProperty: function(attribute, value){
  var EA = Element.Attributes, key = EA.Props[attribute], hasValue = $defined(value);
  if (key && EA.Bools[attribute]) value = (value || !hasValue) ? true : false;
  else if (!hasValue) return this.removeProperty(attribute);
  (key) ? this[key] = value : this.setAttribute(attribute, value);
  return this;
 },

 //批量属性设置
 setProperties: function(attributes){
  for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
  return this;
 },

 //移除属性
 removeProperty: function(attribute){
  var EA = Element.Attributes, key = EA.Props[attribute], isBool = (key && EA.Bools[attribute]);
  (key) ? this[key] = (isBool) ? false : '' : this.removeAttribute(attribute);
  return this;
 },

 //批量移除属性
 removeProperties: function(){
  Array.each(arguments, this.removeProperty, this);
  return this;
 }

});

/*----------------------------------------------*/
//模块化写法，就地执行
(function(){

/*
步进访问父/子/兄弟节点，高度抽象，设计比较巧妙
eleemnt 当前节点
walk 指定步进的方式
start 初始节点的位置
match 匹配过滤的标签
all 是否返回所有指定步进中包含的节点
nocash 是否需要对节点进行扩展，默认为false，需要
*/
var walk = function(element, walk, start, match, all, nocash){
 //先确定步进的起始位置
 var el = element[start || walk];
 var elements = [];
 while (el){
  //仅返回HTML Element节点和匹配指定标签的节点(在指定匹配标签时)
  if (el.nodeType == 1 && (!match || Element.match(el, match))){
   elements.push(el);
   //当不需要返回所有符合条件节点时立刻跳出循环
   if (!all) break;
  }
  //移动
  el = el[walk];
 }
 return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : $(elements[0], nocash);
};

Element.implement({

 //获取当前节点前面的同级节点
 getPrevious: function(match, nocash){
  return walk(this, 'previousSibling', null, match, false, nocash);
 },

 //获取当前节点前面所有的同级节点
 getAllPrevious: function(match, nocash){
  return walk(this, 'previousSibling', null, match, true, nocash);
 },

 //获取当前节点后面的同级节点
 getNext: function(match, nocash){
  return walk(this, 'nextSibling', null, match, false, nocash);
 },

 //获取当前节点后面所有的同级节点
 getAllNext: function(match, nocash){
  return walk(this, 'nextSibling', null, match, true, nocash);
 },

 //获取当前节点内的第一个节点
 getFirst: function(match, nocash){
  return walk(this, 'nextSibling', 'firstChild', match, false, nocash);
 },

 //获取当前节点内的最后一个节点
 getLast: function(match, nocash){
  return walk(this, 'previousSibling', 'lastChild', match, false, nocash);
 },

 //获取当前节点的上级节点
 getParent: function(match, nocash){
  return walk(this, 'parentNode', null, match, false, nocash);
 },

 //获取当前节点的所有祖先
 getParents: function(match, nocash){
  return walk(this, 'parentNode', null, match, true, nocash);
 },

 //获取当前节点的所有子节点
 getChildren: function(match, nocash){
  return walk(this, 'nextSibling', 'firstChild', match, true, nocash);
 },

 //判断是否包含指定子节点
 hasChild: function(el){
  el = $(el, true);
  return (!!el && $A(this.getElementsByTagName(el.tagName)).contains(el));
 }

});

})();

/*----------------------------------------------*/
//用于特殊属性的setter和getter
Element.Properties = new Hash;

/*
style的getter和setter
可以使用element.set('style', value)来设置值
*/
Element.Properties.style = {

 set: function(style){
  this.style.cssText = style;
 },

 get: function(){
  return this.style.cssText;
 },

 erase: function(){
  this.style.cssText = '';
 }

};

/*
标签名的getter，注意没有setter，所以是只读属性，如：
element.get('tag');
*/
Element.Properties.tag = {get: function(){
 return this.tagName.toLowerCase();
}};

/*
A的href的getter
虽然没有setter，但不代表是只读
因为是属性，所以可以直接 element.set('href', value)
之所以单独写，是因为默认取href属性值返回的是浏览器根据路径规则解释过的绝对地址
而我们通常要的是属性原值
*/
Element.Properties.href = {get: function(){
 return (!this.href) ? null : this.href.replace(new RegExp('^' + document.location.protocol + '\/\/' + document.location.host), '');
}};

//innerHTML的快捷方式，支持可变参数，能避免长串的字符串连接
Element.Properties.html = {set: function(){
 return this.innerHTML = Array.flatten(arguments).join('');
}};

//为Element、Window和Document添加扩展实现
Native.implement([Element, Window, Document], {

 //添加事件监听
 addListener: function(type, fn){
  if (this.addEventListener) this.addEventListener(type, fn, false);
  else this.attachEvent('on' + type, fn);
  return this;
 },

 //移除事件监听
 removeListener: function(type, fn){
  if (this.removeEventListener) this.removeEventListener(type, fn, false);
  else this.detachEvent('on' + type, fn);
  return this;
 },

 //获取已保存的临时对象实例，如果对象不存在，将引用指向dflt(如果提供此参数)
 retrieve: function(property, dflt){
  var storage = Element.Storage.get(this.uid);
  var prop = storage[property];
  if ($defined(dflt) && !$defined(prop)) prop = storage[property] = dflt;
  return $pick(prop);
 },

 //保存临时对象
 store: function(property, value){
  var storage = Element.Storage.get(this.uid);
  storage[property] = value;
  return this;
 },

 //删除临时对象
 eliminate: function(property){
  var storage = Element.Storage.get(this.uid);
  delete storage[property];
  return this;
 }

});

//Element的几类属性，只是素材的准备，下面就地执行的匿名函数会进行加工处理，以方便别处的调用
Element.Attributes = new Hash({
 Props: {'html': 'innerHTML', 'class': 'className', 'for': 'htmlFor', 'text': (Browser.Engine.trident) ? 'innerText' : 'textContent'},
 Bools: ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer'],
 Camels: ['value', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap']
});

//对Element的加工处理
(function(EA){

 var EAB = EA.Bools, EAC = EA.Camels;
 //将Bools转成Props的格式
 EA.Bools = EAB = EAB.associate(EAB);
 //将Camels转成Props的格式，合并到Props
 Hash.extend(Hash.combine(EA.Props, EAB), EAC.associate(EAC.map(function(v){
  return v.toLowerCase();
 })));
 //删除Camels属性
 EA.erase('Camels');

})(Element.Attributes);

/*----------------------------------------------*/
//Element事件的setter，addEvents的快捷方式

Element.Properties.events = {set: function(events){
 this.addEvents(events);
}};

//Element、Window 和 Document的事件扩展
Native.implement([Element, Window, Document], {
 //添加事件监听，有别于addListener，可以使用自定义事件
 addEvent: function(type, fn){
  //取临时对象，注意提供的默认值
  var events = this.retrieve('events', {});
  //查找指定类型的事件列表
  events[type] = events[type] || {'keys': [], 'values': []};
  //如果已经添加了该监听
  if (events[type].keys.contains(fn)) return this;
  //添加到事件订阅列表
  events[type].keys.push(fn);

  var realType = type, custom = Element.Events.get(type), condition = fn, self = this;
  //如果是自定义事件
  if (custom){
   //添加自定义事件时的处理
   if (custom.onAdd) custom.onAdd.call(this, fn);
   //自定义事件的条件
   if (custom.condition){
    condition = function(event){
     if (custom.condition.call(this, event)) return fn.call(this, event);
     return false;
    };
   }
   realType = custom.base || realType;
  }
  var defn = function(){
   return fn.call(self);
  };
  //内置事件类型处理
  var nativeEvent = Element.NativeEvents[realType] || 0;
  //如果是内置的事件
  if (nativeEvent){
   //如果是交互事件
   if (nativeEvent == 2){
    //闭包
    defn = function(event){
     //这样最后传给监听函数的参数是经包装过Event对象
     event = new Event(event, self.getWindow());
     //这个条件用于扩展内置事件
     if (condition.call(self, event) === false) event.stop();
    };
   }
   //最终还是调用addListener
   this.addListener(realType, defn)
  }
  //添加到列表
  events[type].values.push(defn);
  return this;
 },


 //移除事件监听
 removeEvent: function(type, fn){
  //取临时对象，不提供默认值
  var events = this.retrieve('events');
  //如果临时对象不存在，说明监听不存在，直接返回
  if (!events || !events[type]) return this;
  //检查是否已添加本监听
  var pos = events[type].keys.indexOf(fn);
  //没有则返回
  if (pos == -1) return this;
  

  //从队列中移除
  var key = events[type].keys.splice(pos, 1)[0];
  var value = events[type].values.splice(pos, 1)[0];

  //自定义事件处理
  var custom = Element.Events.get(type);
  //如果是自定义事件
  if (custom){
   //自定义事件的移除处理
   if (custom.onRemove) custom.onRemove.call(this, fn);
   type = custom.base || type;
  }
  //如果是内置事件还需要调用removeListener来处理
  return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;
 },

 //批量添加事件监听
 addEvents: function(events){
  for (var event in events) this.addEvent(event, events[event]);
  return this;
 },
 
 //批量移除事件监听
 removeEvents: function(type){
  //取临时对象，不提供默认值
  var events = this.retrieve('events');
  //没有事件监听直接返回

  if (!events) return this;
  //如果不提供type参数，移除所有类型的事件
  if (!type){
   for (var evType in events) this.removeEvents(evType);
   events = null;
  } else if (events[type]){
   //移除指定类型的事件
   while (events[type].keys[0]) this.removeEvent(type, events[type].keys[0]);
   events[type] = null;
  }
  return this;
 },

 

 //事件通知
 fireEvent: function(type, args, delay){
  //取临时对象，不提供默认值
  var events = this.retrieve('events');
  //没有事件监听
  if (!events || !events[type]) return this;
  events[type].keys.each(function(fn){
   //注意事件监听的函数中this默认指向当前Element
   fn.create({'bind': this, 'delay': delay, 'arguments': args})();
  }, this);
  return this;
 },

 //事件复制
 cloneEvents: function(from, type){
  //事件源
  from = $(from);

  var fevents = from.retrieve('events');
  if (!fevents) return this;
  //不提供type参数则复制所有事件
  if (!type){
   for (var evType in fevents) this.cloneEvents(from, evType);
  } else if (fevents[type]){
   //复制指定类型的事件
   fevents[type].keys.each(function(fn){
    this.addEvent(type, fn);
   }, this);
  }
  return this;
 }
});


//内置事件，分两种类型
Element.NativeEvents = {
 click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
 mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
 mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
 keydown: 2, keypress: 2, keyup: 2, //keyboard
 focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements
 load: 1, unload: 1, beforeunload: 1, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
 error: 1, abort: 1, scroll: 1 //misc
};


//就地执行的匿名函数
(function(){
var $check = function(event){
 var related = event.relatedTarget;
 if (related == undefined) return true;
 if (related === false) return false;
 return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related));
};


//基于原事件扩展出的自定义事件
Element.Events = new Hash({
 //鼠标进入事件
 mouseenter: {
  base: 'mouseover',
  condition: $check
 },
 //鼠标离开事件
 mouseleave: {
  base: 'mouseout',
  condition: $check
 },
 //鼠标滚轮事件
 mousewheel: {
  base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel'
 }
});
})();

/*----------------------------------------------*/
//Element的styles的setter，setStyles的快捷方式
Element.Properties.styles = {set: function(styles){
 this.setStyles(styles);
}};

//Element的透明度控制在浏览器间差异较大，所以单独处理
Element.Properties.opacity = {
 set: function(opacity, novisibility){
  //如果没有指定不控制visibility样式(即仅当novisibility参数为true时不处理)
  if (!novisibility){
   //所以要控制隐藏与显示，可以用this.set('opacity', 1)和this.set('opacity', 0)来控制
   if (opacity == 0){
    //透明度为0时直接隐藏
    if (this.style.visibility != 'hidden') this.style.visibility = 'hidden';
   } else {
    //透明度为1时直接显示
    if (this.style.visibility != 'visible') this.style.visibility = 'visible';
   }
  }
  //修正ie hasLayout的bug
  if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
  //ie的透明度控制用滤镜，注意两种opacity值的区别
  if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')';
  //非ie直接用opacity样式属性
  this.style.opacity = opacity;

  //存到临时对象，以避免读取时再次进行兼容性判断和操作
  this.store('opacity', opacity);
 },

 //直接取临时对象数据，省却兼容性问题
 get: function(){
  return this.retrieve('opacity', 1);
 }
};

Element.implement({
 //设置透明度的快捷方式
 setOpacity: function(value){
  return this.set('opacity', value, true);
 },
 //获取透明度
 getOpacity: function(){
  return this.get('opacity');
 },
 //样式设置
 setStyle: function(property, value){
  //两个特殊属性
  switch (property){
   case 'opacity': return this.set('opacity', parseFloat(value));
   case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
  }
  /*
  转成骆驼表示，所以其实这里的样式属性同时支持两种写法，如
  setStyle('borderTopWith', 1) 和 setStyle('border-top-with', 1)
  */
  property = property.camelCase();
  if ($type(value) != 'string'){
   var map = (Element.Styles.get(property) || '@').split(' ');
   //处理多属性简写时的赋值
   value = $splat(value).map(function(val, i){
    if (!map[i]) return '';
    return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
   }).join(' ');
  } else if (value == String(Number(value))){
   value = Math.round(value);
  }
  this.style[property] = value;
  return this;
 },

 //获取样式值
 getStyle: function(property){
  //还是那两个特殊属性
  switch (property){
   case 'opacity': return this.get('opacity');
   case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
  }
  //还是支持两种写法
  property = property.camelCase();
  var result = this.style[property];
  //如果取不到值(通常是因为是简写的属性或者属性是在css中指定)
  if (!$chk(result)){
   result = [];
   //将简写属性还原，逐个取值
   for (var style in Element.ShortStyles){
    if (property != style) continue;
    for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
    return result.join(' ');
   }
   //另一种可能，样式是在<style>中指定或者外部css文件指定，这时需要获取运行时的样式值
   result = this.getComputedStyle(property);
  }
  if (result){
   //颜色处理，将RGB表示转成HEX表示
   result = String(result);
   var color = result.match(/rgba?\([\d\s,]+\)/);
   if (color) result = result.replace(color[0], color[0].rgbToHex());
  }
  //在Opera和IE下，获取width和height的处理
  if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result)))){
   //IE和Opera的width不会计算边框厚度，而遵循w3c标准的Fx会
   if (property.test(/^(height|width)$/)){
    var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
    values.each(function(value){
     size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
    }, this);
    //用offsetWidth/offsetHeight减相应方向的边框厚度即为所求
    return this['offset' + property.capitalize()] - size + 'px';
   }
   if (Browser.Engine.presto && String(result).test('px')) return result;
   if (property.test(/(border(.+)Width|margin|padding)/)) return '0px';
  }
  return result;
 },

 //批量设置样式
 setStyles: function(styles){
  for (var style in styles) this.setStyle(style, styles[style]);
  return this;
 },

 //批量获取样式
 getStyles: function(){
  var result = {};
  Array.each(arguments, function(key){
   result[key] = this.getStyle(key);
  }, this);
  return result;
 }

});

//一些特殊的样式，只是待加工的材料
Element.Styles = new Hash({
 left: '@px', top: '@px', bottom: '@px', right: '@px',
 width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
 backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
 fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
 margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
 borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
 zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
});

//一些缮写的样式，只是待加工的材料
Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};

//对Element.Styles和Element.ShortStyles的再加工
['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
 var Short = Element.ShortStyles;
 var All = Element.Styles;
 //构造marginTop，paddingTop之类的属性
 ['margin', 'padding'].each(function(style){
  var sd = style + direction;
  Short[style][sd] = All[sd] = '@px';
 });
 //构造borderTopWith之类的属性
 var bd = 'border' + direction;
 Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
 var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
 Short[bd] = {};
 Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
 Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
 Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
});

/*----------------------------------------------*/
/*
本部分主要为Element提供取尺寸相关的兼容方法
*/
(function(){
Element.implement({
 //使可视范围滚动到指定坐标
 scrollTo: function(x, y){
  //如果当前是body，让页面的滚动条滚动
  if (isBody(this)){
   this.getWindow().scrollTo(x, y);
  } else {
   this.scrollLeft = x;
   this.scrollTop = y;
  }
  return this;
 },
 //获取对象的布局尺寸
 getSize: function(){
  if (isBody(this)) return this.getWindow().getSize();
  return {x: this.offsetWidth, y: this.offsetHeight};
 },

 //获取对象的滚动尺寸
 getScrollSize: function(){
  if (isBody(this)) return this.getWindow().getScrollSize();
  return {x: this.scrollWidth, y: this.scrollHeight};
 },

 //获取滚动位置
 getScroll: function(){
  if (isBody(this)) return this.getWindow().getScroll();
  return {x: this.scrollLeft, y: this.scrollTop};
 },

 //获取相对文档的滚动位置
 getScrolls: function(){
  var element = this, position = {x: 0, y: 0};
  while (element && !isBody(element)){
   position.x += element.scrollLeft;
   position.y += element.scrollTop;
   element = element.parentNode;
  }
  return position;
 },

 //获取总的偏移量
 getOffsets: function(){
  var element = this, position = {x: 0, y: 0};
  //如果是根节点,坐标为原点
  if (isBody(this)) return position;

  while (element && !isBody(element)){
   position.x += element.offsetLeft;
   position.y += element.offsetTop;

   if (Browser.Engine.gecko){
    //firefox的处理,如果不使用盒模型,需要加上左和上边框的宽度
    if (!borderBox(element)){
     position.x += leftBorder(element);
     position.y += topBorder(element);
    }
    var parent = element.parentNode;
    if (parent && styleString(parent, 'overflow') != 'visible'){
     position.x += leftBorder(parent);
     position.y += topBorder(parent);
    }
   } else if (element != this && (Browser.Engine.trident || Browser.Engine.webkit)){
    //IE和Safari也需要加上边框,看来这里只有Opera比较符合标准,Safari次之
    position.x += leftBorder(element);
    position.y += topBorder(element);
   }

   element = element.offsetParent;
   if (Browser.Engine.trident){
    //忽略IE下没有hasLayout的element
    while (element && !element.currentStyle.hasLayout) element = element.offsetParent;
   }
  }
  //firefox下不使用盒模型解决时需要再减去当前的上左边框宽度
  if (Browser.Engine.gecko && !borderBox(this)){
   position.x -= leftBorder(this);
   position.y -= topBorder(this);
  }
  return position;
 },

 //获取坐标值,如果提供relative参数,则返回相对于ralative的坐标值
 getPosition: function(relative){
  //根节点坐标为原点
  if (isBody(this)) return {x: 0, y: 0};
  //取偏移值和滚动条位置
  var ōffset = this.getOffsets(), scroll = this.getScrolls();
  //得到坐标值
  var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
  //求相对坐标值
  var relativePosition = (relative && (relative = $(relative))) ? relative.getPosition() : {x: 0, y: 0};
  return {x: position.x - relativePosition.x, y: position.y - relativePosition.y};
 },

 //获取坐标和尺寸
 getCoordinates: function(element){
  //根节点处理
  if (isBody(this)) return this.getWindow().getCoordinates();
  //分别获取坐标与尺寸
  var position = this.getPosition(element), size = this.getSize();
  //新的表示形式
  var ōbj = {left: position.x, top: position.y, width: size.x, height: size.y};
  //右下坐标的计算
  obj.right = obj.left + obj.width;
  obj.bottom = obj.top + obj.height;
  return obj;
 },

 //计算运行时坐标,会受margin-left和margin-top影响
 computePosition: function(obj){
  return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')};
 },

 //定位
 position: function(obj){
  return this.setStyles(this.computePosition(obj));
 }

});

//对Document和Window实现Element的同名方法,因为具体实现有别于一般Element
Native.implement([Document, Window], {

 //获取尺寸
 getSize: function(){
  var win = this.getWindow();
  //Opera和Safari的处理
  if (Browser.Engine.presto || Browser.Engine.webkit) return {x: win.innerWidth, y: win.innerHeight};
  var doc = getCompatElement(this);
  return {x: doc.clientWidth, y: doc.clientHeight};
 },

 //获取滚动坐标
 getScroll: function(){
  var win = this.getWindow();
  var doc = getCompatElement(this);
  return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
 },

 //获取滚动尺寸
 getScrollSize: function(){
  var doc = getCompatElement(this);
  var min = this.getSize();
  return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)};
 },

 //定位
 getPosition: function(){
  return {x: 0, y: 0};
 },

 //获取尺寸和坐标
 getCoordinates: function(){
  var size = this.getSize();
  return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
 }

});

// 私有方法

//获取运行时的样式属性
var styleString = Element.getComputedStyle;

//获取运行时的样式属性的数字值
function styleNumber(element, style){
 return styleString(element, style).toInt() || 0;
};

//获取盒尺寸的mozilla家庭私有属性
function borderBox(element){
 return styleString(element, '-moz-box-sizing') == 'border-box';
};

//获取上边框的宽度
function topBorder(element){
 return styleNumber(element, 'border-top-width');
};

//获取左边框宽度
function leftBorder(element){
 return styleNumber(element, 'border-left-width');
};

//测试element是否body或html节点
function isBody(element){
 return (/^(?:body|html)$/i).test(element.tagName);
};

//根据当前文档是否使用标准模式而返回页面根节点,html或body
function getCompatElement(element){
 var doc = element.getDocument();
 return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
};

})();

//别名

Native.implement([Window, Document, Element], {

 //获取高度,依赖getSize方法
 getHeight: function(){
  return this.getSize().y;
 },

 //获取宽度,依赖getSize方法
 getWidth: function(){
  return this.getSize().x;
 },

 //获取y轴滚动坐标,依赖getScroll方法
 getScrollTop: function(){
  return this.getScroll().y;
 },

 //获取x轴滚动坐标,依赖getScroll方法
 getScrollLeft: function(){
  return this.getScroll().x;
 },

 //获取滚动高度,依赖getScrollSize方法
 getScrollHeight: function(){
  return this.getScrollSize().y;
 },

 //获取滚动宽度,依赖getScrollSize方法
 getScrollWidth: function(){
  return this.getScrollSize().x;
 },

 //获取y坐标,依赖getPosition方法
 getTop: function(){
  return this.getPosition().y;
 },

 //获取x坐标,依赖getPosition方法
 getLeft: function(){
  return this.getPosition().x;
 }

});